package com.xcity.game.battle.pve;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Player;
import com.xcity.game.battle.BattleContext;
import com.xcity.game.battle.BattleException;
import com.xcity.game.battle.BattleResult.PVEResult;
import com.xcity.game.battle.BattleState;
import com.xcity.game.battle.pve.employee.EmployeeSkillBattleContext;
import com.xcity.game.battle.pve.template.StageTemplate;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.MessageConst;
import com.xcity.game.employee.skill.EmployeeSkill;
import com.xcity.game.employee.skill.SkillGroups2;
import com.xcity.game.event.GameEvents;
import com.xcity.game.item.ItemEffect;
import com.xcity.game.item.ItemInfo;
import com.xcity.game.item.drop.Drop;
import com.xcity.game.item.drop.impl.ExpDrop;
import com.xcity.game.item.drop.impl.GoldDrop;
import com.xcity.game.item.drop.impl.ItemDrop;
import com.xcity.pomelo.push.msg.PVEStageEndPush;
import com.xcity.pomelo.request.PVEAttackRequest;
import com.xcity.pomelo.request.PVEStageFightEndRequest;
import com.xcity.pomelo.response.PVEStageFightResponse.BlockInfo;
import com.xcity.pomelo.response.PVEStageResultResponse;

import naga.x.App;
import naga.x.game.time.TimeUpdater;
import naga.x.util.CommonUtils;

@Deprecated
public class PVEBattle extends BattleContext {

	protected Player player;
	protected PVEStage stage;
	protected List<Employee> employees; // 携带的员工
	protected List<ItemInfo> items; // 携带的物品
	protected BattleState state = BattleState.READY;
	protected long createTime;
	protected long lastPauseTime;
	protected int pausedMillis;
	protected int addedMillis; // 延长时间
	protected boolean syncStep, moving;
	protected List<EmployeeSkill> triggeredSkills; // 纪录每轮触发的技能(获取一次即清空)
	
	public static /*final*/ int MAX_DROP_ITEM_SIZE = 8; // 最多掉落8组物品
	@Deprecated
	public static final int PLAYER_GAIN_EXP_PERCENT = 40; // 角色获得经验40%,其余由员工平分
	protected static final int DELAY = 10000;
	protected static final Logger LOG = PVEService.LOG;
	
	public PVEBattle(Player player, PVEStage stage, List<Employee> employees, List<ItemInfo> items) {
		super(new PlayerBattler(player, employees), new NPCBattler(stage.getTemplate()));
		this.player = player;
		this.stage = stage;
		this.employees = employees;
		this.items = items != null ? items : Collections.emptyList();
		this.createTime = TimeUpdater.getInstance().now();
		init();
	}
	
	public boolean isEnd() {
		if (state == BattleState.READY || state == BattleState.PAUSE) {
			return false;
		}
		if (state == BattleState.END) {
			return true;
		}
		long n = createTime + stage.getTemplate().getTimeLimit() * 1000 + pausedMillis + addedMillis - TimeUpdater.getInstance().now();
		return n + DELAY <= 0; // 延迟10秒
	}
	
	public void begin() {
		if (state == BattleState.READY) {
			createTime = TimeUpdater.getInstance().now();
			state = BattleState.BEGIN;
		}
	}
	
	public String pause() {
		if (state == BattleState.READY) {
			return MessageConst.PVE_NOT_BEGIN;
		}
		if (state == BattleState.PAUSE) {
			return MessageConst.PVE_PAUSED;
		}
		if (state == BattleState.END) {
			return MessageConst.PVE_ENDED;
		}
		state = BattleState.PAUSE;
		lastPauseTime = TimeUpdater.getInstance().now();
		LOG.info("[PVE PAUSE]ID[{}]STAGE[{}]", player.getId(), stage.getId());
		return null;
	}
	
	public String goOn() {
		if (state == BattleState.PAUSE) {
			pausedMillis += (int) (TimeUpdater.getInstance().now() - lastPauseTime);
			state = BattleState.BEGIN;
			LOG.info("[PVE GOON]ID[{}]STAGE[{}]", player.getId(), stage.getId());
			return null;
		}
		if (state == BattleState.READY) {
			return MessageConst.PVE_NOT_BEGIN;
		}
		return MessageConst.OP_TIME_OUT;
	}
	
	public void end(String cause) {
		end(null, cause);
	}
	
	public void end(PVEStageFightEndRequest req, String cause) {
		if (state == BattleState.END) {
			return;
		}
		state = BattleState.END;
		int star = settle(req);
		stage.end(star);
		returnStrIfFail(star);
		LOG.info("[PVE END]ID[{}]STAGE[{}]RESULT[{}]CAUSE[{}]", player.getId(), stage.getId(), star, cause);
	}
	
	/**
	 * 结算战斗结果
	 * @param req
	 * @return
	 */
	private int settle(PVEStageFightEndRequest req) {
		int star = PVEResult.FAIL.ordinal();
		if (req == null) {
			player.send(new PVEStageEndPush(stage.getId(), star));
			return star;
		}
		// 扣除消耗道具
		List<ItemInfo> removeItems = req.getItems();
		boolean useAddHpItem = false;
		for (int i = 0, size = removeItems.size(); i < size; i++) {
			ItemInfo item = removeItems.get(i);
			if (item.getCount() > 0) {
				boolean succ = player.getBag().removeItem(item.getId(), item.getCount(), Cause.PVE_END);
				if (!succ) {
					LOG.info("[REMOVE ITEM FAIL]ID[{}]ITEM[{}={}]CAUSE[{}]", player.getId(), item.getId(), item.getCount(), Cause.PVE_END);
				} else if (item.getTemplate().getEffect() == ItemEffect.PVE_ADD_HP) {
					useAddHpItem = true;
				}
			}
		}
		int[] clearBlocks = wrapBlocks(req.getClears());
		StringBuilder logCalc = new StringBuilder("[PVE END CALC]ID[{}]STAGE[{}]REQ[{}]HP[{}]ENEMYHP[{}]");
//		if (req.getEnemyHP() <= 0
////						&& (calcPlayerHP(logCalc) > 0 || useAddHpItem) // TODO 先不判断
//				&& calcEnemyHP(clearBlocks, logCalc) == 0) { // 胜利必要条件
		if (getTarget().getHp() <= 0) {
			star++;
			if (TimeUpdater.getInstance().now() - createTime <= stage.getTemplate().getTimeLimit() * 500/*1000 / 2*/) {
				// 耗时一半以内
				star++;
			}
			if ((stage.getTemplate().getStep() == StageTemplate.STEP_NO_LIMIT || (req.getStep() > 0 && req.getStep() <= stage.getTemplate().getStep()))
					|| clearBlocksMatch(clearBlocks)) {
				// 额外条件(步数、消除色块数)
				star++;
			}
		}
		LOG.info(logCalc.toString(), player.getId(), stage.getId(), req.getEnemyHP(), getSource().getHp(), getTarget().getHp());
		List<Drop> drops = Collections.emptyList();
		float addedRatio = 0f;
		if (star != PVEResult.FAIL.ordinal()) { // 胜利 处理掉落
			List<Drop> allDrops = stage.getStar() == 0 ?
					stage.getTemplate().getPassRewardsDrop()[star - 1] // 第一次通关奖励
							: stage.getTemplate().getRewardsDrop();
			List<Drop> itemDrops = new ArrayList<Drop>(allDrops.size());
			drops = new ArrayList<Drop>(allDrops.size());
			int employeeSize = employees.size();
			// 收入加成技能
			addedRatio = ((PlayerBattler) getSource()).batchCalcFloat(SkillGroups2.RAISE_REWARD_EXP_AND_MONEY);
			for (int i = 0; i < allDrops.size(); i++) {
				Drop drop = allDrops.get(i);
				// 经验、物品掉落特殊处理
				if (employeeSize > 0 && drop instanceof ExpDrop) {
					// 需要与员工分享经验
					int exp = ((ExpDrop) drop).getExp();
					int expAdded = 0;
					if (addedRatio > 0) {
						expAdded = (int) (exp * addedRatio);
					}
					int playerGainExp = exp * PLAYER_GAIN_EXP_PERCENT / GameStaticConfig.percentBase;
					player.addExp(playerGainExp, Cause.PVE_END);
					if (expAdded > 0) {
						player.addExp(expAdded, Cause.EMPLOYEE_SKILL_TRIGGERED);
					}
					exp = (exp - playerGainExp) / employeeSize;
					for (int j = 0; j < employeeSize; j++) {
						Employee e = employees.get(j);
						e.addExp(exp, Cause.PVE_END);
						if (expAdded > 0) {
							e.addExp(expAdded, Cause.EMPLOYEE_SKILL_TRIGGERED);
						}
					}
					drops.add(drop);
				} else if (drop instanceof ItemDrop) {
					itemDrops.add(drop);
				} else {
					drop.drop(player, Cause.PVE_END);
					drops.add(drop);
					if (addedRatio > 0 && drop instanceof GoldDrop) {
						int gold = (int) (((GoldDrop) drop).getGold() * addedRatio);
						player.addGold(gold, Cause.EMPLOYEE_SKILL_TRIGGERED);
					}
				}
			}
			// 物品最多只掉落3个
			CommonUtils.shuffle(itemDrops);
			for (int i = 0, size = MAX_DROP_ITEM_SIZE < itemDrops.size() ? MAX_DROP_ITEM_SIZE : itemDrops.size(); i < size; i++) {
				Drop drop = itemDrops.get(i);
				if (drop.drop(player, Cause.PVE_END)) {
					drops.add(drop);
				}
			}
		}
		PVEStageResultResponse res = new PVEStageResultResponse(req.getSerial(), req.getId(), star, drops, addedRatio);
		player.send(res);
		if (star > 0) {
			App.getApp().getEventManager().addEvent(GameEvents.EVENT_PVE_SUCCESS, player, stage, star, drops, stage.getPassTime() == 0);
		}
		return star;
	}
	
	public ItemInfo getItem(int itemId) {
		List<ItemInfo> items = this.items;
		for (int i = 0; i < items.size(); i++) {
			ItemInfo item = items.get(i);
			if (item.getId() == itemId) {
				return item;
			}
		}
		return null;
	}
	
	public ItemInfo useItem(int itemId, int count) throws PVEException {
		if (state == BattleState.READY) {
			throw new PVEException(MessageConst.PVE_NOT_BEGIN);
		}
		if (state == BattleState.END) {
			throw new PVEException(MessageConst.PVE_ENDED);
		}
		ItemInfo item = getItem(itemId);
		if (item == null) {
			throw new PVEException(MessageConst.ITEM_NOT_ENOUGH2);
		}
		if (item.getCount() >= count) {
			item.setCount(item.getCount() - count);
			boolean succ = player.getBag().removeItem(item.getId(), count, Cause.PVE_USE_ITEM);
			if (succ) {
				switch (item.getTemplate().getEffect()) {
				case ItemEffect.PVE_ADD_TIME:
					addedMillis += item.getTemplate().getParameter(0) * count * 1000;
					break;
				case ItemEffect.PVE_ADD_HP:
					getSource().setHp(getSource().getHp() + getSource().getMaxHp() / 2);
					break;
				}
				return item;
			}
		}
		throw new PVEException(MessageFormat.format(MessageConst.ITEM_NOT_ENOUGH, item.getTemplate().getName()));
	}
	
	private int calcPlayerHP(StringBuilder log) {
		int enemyAttack = stage.getTemplate().getEnemyAttack();
		int enemyAttackCD = stage.getTemplate().getEnemyAttackCD() * 1000;
		// 计算敌方攻击次数
		int n = (int) ((TimeUpdater.getInstance().now() - createTime - DELAY/*延迟10秒*/) / enemyAttackCD);
		int val = /*PlayerUtils.getHP(player)*/player.getHp() - n * enemyAttack;
		log.append("ENEMYATT[").append(n).append('=').append(val).append(']');
		return val > 0 ? val : 0;
	}
	
	private int calcEnemyHP(int[] clearBlocks, StringBuilder log) {
		int n = 0;
		// 计算玩家攻击次数
		log.append("PLAYERATT[");
		for (int num : clearBlocks) {
			int t = num / stage.getTemplate().getAttackNeedBlockNum();
			n += t;
			log.append(t).append(',');
		}
		log.setLength(log.length() - 1);
		int val = stage.getTemplate().getEnemyHP() - n * PVEUtils.calcAttack(player, employees);
		log.append('=').append(val).append(']');
		return val > 0 ? val : 0;
	}
	
	private boolean clearBlocksMatch(int[] clearBlocks) {
		int[] needClearBlocks = stage.getTemplate().getClearBlocks();
		if (needClearBlocks != null) {
			for (int i = 0; i < needClearBlocks.length; i++) {
				if (clearBlocks[i] < needClearBlocks[i]) {
					return false;
				}
			}
		}
		return true;
	}
	
	private static int[] wrapBlocks(List<BlockInfo> clears) {
		int[] blocks = new int[StageBlockType.ALL.length];
		for (int i = 0, size = clears != null ? clears.size() : 0; i < size; i++) {
			BlockInfo info = clears.get(i);
			int index = info.getIndex();
			if (index >= 0 && index < blocks.length) {
				blocks[index] = info.getNum();
			}
		}
		return blocks;
	}
	
	/**
	 * 挑战失败需返体力
	 * @param star
	 */
	private void returnStrIfFail(int star) {
		if (star <= 0) {
			player.addStrength(stage.getTemplate().getCostStr(), Cause.PVE_FAIL);
		}
	}

	@Override
	public void init() {
	}

	@Override
	public void attack(Object param) throws BattleException {
		PVEAttackRequest req = (PVEAttackRequest) param;
		PlayerBattler player = getSource();
		NPCBattler target = getTarget();
		if (req.getEid() > 0 && req.getSkillId() > 0) {
			// 使用主动技能
			EmployeeSkillBattleContext ctx = player.getSkillContext(req.getEid(), req.getSkillId());
			if (ctx == null) {
				throw new BattleException(MessageConst.SKILL_NOT_FOUND);
			}
			ctx.trigger();
		} else { // 普攻
			// preHint
				// 秒杀
			if (player.batchTrigger(SkillGroups2.SKILL_36)) {
				return;
			}
				// 加攻
			player.batchTrigger(SkillGroups2.RAISE_ATTACK_LAST_N_TIMES);
			// hint
			target.setHp(target.getHp() - player.getAttack());
			// afterHint
				// 额外伤害
			player.batchTrigger(SkillGroups2.DOUBLE_DAMAGE);
			player.batchTrigger(SkillGroups2.EXTRA_DAMAGE);
		}
	}

	@Override
	public void defense() throws BattleException {
		PlayerBattler player = getSource();
		NPCBattler target = getTarget();
		// pre
			// 无敌技能
		if (player.batchTrigger(SkillGroups2.INVINCIBLE_LAST_N_TIMES)) {
			return;
		}
		if (player.batchTrigger(SkillGroups2.DEFENSE_SHIELD_BUFF)) {
			return;
		}
			// 攻击无效
		if (player.batchTrigger(SkillGroups2.SKILL_42)) {
			return;
		}
		// hint
		player.setHp(player.getHp() - target.getAttack());
		// after
			// 减伤
		player.batchTrigger(SkillGroups2.SKILL_40);
			// 恢复hp技能
		player.batchTrigger(SkillGroups2.RECOVER_HP_AFTER_BE_ATTACKED);
		player.batchTrigger(SkillGroups2.SKILL_37);
			// 加攻
		player.batchTrigger(SkillGroups2.SKILL_39);
			// 反弹伤害
		player.batchTrigger(SkillGroups2.SKILL_43);
			// 恢复
		boolean succ = player.batchTrigger(SkillGroups2.RECOVER_HP_BUFF);
		if (succ) {
			syncStep = true;
		}
	}
	
	public void moveStep() {
		moving = true;
		PlayerBattler player = getSource();
		try {
			boolean succ = player.batchTrigger(SkillGroups2.RECOVER_HP_BUFF);
			if (!succ) {
				syncStep = false;
			}
		} catch (BattleException e) {
			e.printStackTrace();
			syncStep = false;
		}
		moving = false;
	}
	
	public boolean isMoving() {
		return moving;
	}

	public void triggered(EmployeeSkill skill) {
		if (triggeredSkills == null) {
			triggeredSkills = new ArrayList<EmployeeSkill>(2);
		}
		triggeredSkills.add(skill);
	}
	
	public EmployeeSkill getTriggeredSkill() {
		EmployeeSkill skill = null;
		if (triggeredSkills != null && triggeredSkills.size() > 0) {
			skill = triggeredSkills.get(0);
			triggeredSkills.clear();
		}
		return skill;
	}
	
}
